package fem2.observer;

import inf.jlinalg.ArrayVector;
import inf.jlinalg.IVector;

import java.io.IOException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

import fem2.Element;
import fem2.Mesh;
import fem2.Model;
import fem2.Node;

/**
 * TODO
 * 
 * @author hbui
 * 
 */
public class GidResistantObserver extends GidStructuralObserver {

	public GidResistantObserver(Model m, TimeStepObserver o, String projectDir, String projectName) {
		super(m, o, projectDir, projectName);
	}

	public GidResistantObserver(Model m, TimeStepObserver o, String projectDir, String projectName,
			String fileName) {
		super(m, o, projectDir, projectName, fileName);
	}

	private Map<Node, Integer> nodeIndexInRe = new HashMap<Node, Integer>();
	private double[][] values;

	@Override
	public void fireStarted() {
		/*
		 * perform a dummy enumeration
		 */
		Mesh mesh = getModel().getMesh();
		for (int i = 0; i < mesh.countNodes(); i++) {
			Node n = mesh.getNode(i);
			nodeIndexInRe.put(n, i);
		}
		/*
		 * initialize value containers
		 */
		int dim = mesh.getDimension();
		values = new double[mesh.countNodes()][dim];
	}

	@Override
	public void fireTimeStepStarted() {
		/*
		 * zero all values
		 */
		for (double[] v : values) {
			Arrays.fill(v, 0.0);
		}
	}

	@Override
	public void fireIterationStarted() {

	}

	@Override
	public void fireIterationFinished() {

	}

	@Override
	public void fireTimeStepFinished() {
		double timeStep = timeStepObserver.getCurrentTimeStep();

		/*
		 * compute all internal force and contribute to node
		 */
		Mesh mesh = getModel().getMesh();
		int dim = mesh.getDimension();
		for (int i = 0; i < getModel().countElements(); i++) {
			Element e = getModel().getElement(i);
			IVector res = new ArrayVector(e.getMeshPart().countDofs());
			res = (IVector) e.computeRes(res);
			Node[] nodes = e.getMeshPart().getNodes();
			for (int j = 0; j < nodes.length; j++) {
				int id = nodeIndexInRe.get(nodes[j]);
				for (int k = 0; k < dim; k++) {
					values[id][k] += res.get(j * dim + k);
				}
			}
		}
		/*
		 * write to gid
		 */
		String variableName = "RESISTANT_FORCE";
		try {
			gidPost.writeMesh(m, timeStep);
			gidPost.writeNodalVectorResult(variableName, values, timeStep);
		} catch (IOException e) {
			throw new Error("write failed");
		}
	}

	@Override
	public void fireFinished() {
		// TODO Auto-generated method stub

	}

}
